﻿Imports System.Collections.ObjectModel
Imports System.ComponentModel

''' <summary>
''' コンピューターを表すクラスです。
''' </summary>
''' <remarks></remarks>
<DataObject()>
Public NotInheritable Class Computer
  Inherits DomainObject

#Region " プライベートフィールド "
  Private ReadOnly _fullName, _role, _os, _osVer, _osSP, _site As String
#End Region

#Region " フレンドコンストラクター "
  ''' <summary>
  ''' <see cref="DirectoryEntry"/> を指定して <see cref="Computer"/> クラスの新しいインスタンスを初期化します。
  ''' </summary>
  ''' <param name="entry"><see cref="DirectoryEntry"/>。</param>
  ''' <remarks></remarks>
  Friend Sub New(entry As DirectoryEntry)
    MyBase.New(entry)

    entry.Invoke("GetInfoEx", New Object() {"msDS-isGC", "msDS-SiteName"}, 0)
    With entry.Properties
      _fullName = DirectCast(.Item("dNSHostName").Value, String)
      _role = GetRole()   '役割を取得
      _os = DirectCast(.Item("operatingSystem").Value, String)
      _osVer = DirectCast(.Item("operatingSystemVersion").Value, String)
      _osSP = DirectCast(.Item("operatingSystemServicePack").Value, String)
      _site = DirectCast(.Item("msDS-SiteName").Value, String)
    End With
  End Sub
#End Region

#Region " パブリックプロパティ "
  ''' <summary>
  ''' DNS 名を取得します。
  ''' </summary>
  ''' <value></value>
  ''' <returns>DNS 名。</returns>
  ''' <remarks></remarks>
  Public ReadOnly Property FullName As String
    Get
      Return _fullName
    End Get
  End Property

  ''' <summary>
  ''' OS を取得します。
  ''' </summary>
  ''' <value></value>
  ''' <returns>OS。</returns>
  ''' <remarks></remarks>
  Public ReadOnly Property OperatingSystem As String
    Get
      Return _os
    End Get
  End Property

  ''' <summary>
  ''' OS のサービスパックを取得します。
  ''' </summary>
  ''' <value></value>
  ''' <returns>OS のサービスパック。</returns>
  ''' <remarks></remarks>
  Public ReadOnly Property OperatingSystemServicePack As String
    Get
      Return _osSP
    End Get
  End Property

  ''' <summary>
  ''' OS のバージョンを取得します。
  ''' </summary>
  ''' <value></value>
  ''' <returns>OS のバージョン。</returns>
  ''' <remarks></remarks>
  Public ReadOnly Property OperatingSystemVersion As String
    Get
      Return _osVer
    End Get
  End Property

  ''' <summary>
  ''' プライマリ グループ ID を取得します。
  ''' </summary>
  ''' <value></value>
  ''' <returns>プライマリ グループ ID。</returns>
  ''' <remarks></remarks>
  Public ReadOnly Property PrimaryGroupId As Integer
    Get
      If MyBase.IsDisposed Then
        Throw New ObjectDisposedException(Me.GetType().Name)
      End If
      Return Convert.ToInt32(MyBase.Entry.Properties.Item("primaryGroupID").Value)
    End Get
  End Property

  ''' <summary>
  ''' 役割を取得します。
  ''' </summary>
  ''' <value></value>
  ''' <returns>役割。</returns>
  ''' <remarks></remarks>
  Public ReadOnly Property Role As String
    Get
      Return _role
    End Get
  End Property

  ''' <summary>
  ''' サイトを取得します。
  ''' </summary>
  ''' <value></value>
  ''' <returns>サイト。</returns>
  ''' <remarks></remarks>
  Public ReadOnly Property Site As String
    Get
      Return _site
    End Get
  End Property
#End Region

#Region " パブリックメソッド "
  ''' <summary>
  ''' 指定した名前のコンピューターを検索します。このメソッドはデータバインド用です。
  ''' </summary>
  ''' <param name="name">名前。</param>
  ''' <returns>コンピューター。</returns>
  ''' <remarks></remarks>
  <DataObjectMethod(DataObjectMethodType.Select)>
  Public Shared Function FindByName(name As String) As Computer
    Return DirectCast(DirectoryAccess.FindDirectoryObject(name, CategoryType.Computer), Computer)
  End Function

  ''' <summary>
  ''' 所属するグループを取得します。
  ''' </summary>
  ''' <param name="groups">グループのコレクション。</param>
  ''' <returns>所属するグループ。</returns>
  ''' <exception cref="ArgumentNullException"><paramref name="groups"/> が Nothing です。</exception>
  ''' <remarks></remarks>
  Public Function GetBelongGroups(groups As IEnumerable(Of DomainGroup)) As ReadOnlyCollection(Of String)
    If groups Is Nothing Then
      Throw New ArgumentNullException("groups", "groups が Nothing です。")
    End If

    Dim belongGroups = groups.Where(
      Function(group) group.Native.IsMember(MyBase.Entry.Path)).Select(Function(group) group.Name).ToList()
    belongGroups.Add(DirectoryAccess.GroupTokens.Item(Me.PrimaryGroupId))
    belongGroups.Sort()
    Return belongGroups.AsReadOnly()
  End Function

  ''' <summary>
  ''' 指定した名前のコンピューターの所属するグループを取得します。このメソッドはデータバインド用です。
  ''' </summary>
  ''' <param name="name">コンピューター名。</param>
  ''' <returns>コンピューターの所属するグループ。</returns>
  ''' <remarks></remarks>
  <DataObjectMethod(DataObjectMethodType.Select)>
  Public Shared Function GetBelongGroups(name As String) As ReadOnlyCollection(Of String)
    Dim pc = FindByName(name)   'コンピューターを検索
    Dim groups = DirectoryAccess.GetGroups(Of DomainGroup)()  'グループを取得
    Return pc.GetBelongGroups(groups)   '所属するグループを取得
  End Function

  ''' <summary>
  ''' コンピューターの一覧を取得します。このメソッドはデータバインド用です。
  ''' </summary>
  ''' <returns>コンピューターの一覧。</returns>
  ''' <remarks></remarks>
  <DataObjectMethod(DataObjectMethodType.Select)>
  Public Shared Function GetComputers() As IList(Of Computer)
    Return DirectoryAccess.GetComputers()   'コンピューターを取得
  End Function
#End Region

#Region " プライベートメソッド "
  ''' <summary>役割を取得します。</summary>
  ''' <returns>役割。</returns>
  ''' <remarks></remarks>
  Private Function GetRole() As String
    Dim gc = MyBase.Entry.Properties.Item("msDS-isGC").Value
    If gc Is Nothing Then
      Return "ワークステーションまたはサーバー"
    End If

    Return If(Convert.ToBoolean(gc), "グローバル カタログ", "ドメイン コントローラー")
  End Function
#End Region
End Class
